package com.md.api.common.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.md.api.common.config.RedisKeys;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;


@Component
public class WxUtil {

    @Autowired
    private RedisUtil redisUtil;
    private static WxUtil wxUtil;

    @PostConstruct
    public void initRedisUtil() {
        wxUtil = this;
        wxUtil.redisUtil = this.redisUtil;
    }
	
    private static final Logger logger = LoggerFactory.getLogger(WxUtil.class);

    // 凭证获取（GET）
    public final static String token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";

    /**
     * 发送https请求
     *
     * @param requestUrl 请求地址
     * @param requestMethod 请求方式（GET、POST）
     * @param outputStr 提交的数据
     * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
     */
    public static JSONObject httpsRequest(String requestUrl, String requestMethod, String outputStr) {
        JSONObject jsonObject = null;
        try {
            // 创建SSLContext对象，并使用我们指定的信任管理器初始化
            TrustManager[] tm = { new MyX509TrustManager() };
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, tm, new java.security.SecureRandom());
            // 从上述SSLContext对象中得到SSLSocketFactory对象
            SSLSocketFactory ssf = sslContext.getSocketFactory();

            URL url = new URL(requestUrl);
            HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
            conn.setSSLSocketFactory(ssf);

            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            // 设置请求方式（GET/POST）
            conn.setRequestMethod(requestMethod);

            // 当outputStr不为null时向输出流写数据
            if (null != outputStr) {
                OutputStream outputStream = conn.getOutputStream();
                // 注意编码格式
                outputStream.write(outputStr.getBytes(StandardCharsets.UTF_8));
                outputStream.close();
            }

            // 从输入流读取返回内容
            InputStream inputStream = conn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String str = null;
            StringBuffer buffer = new StringBuffer();
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }

            // 释放资源
            bufferedReader.close();
            inputStreamReader.close();
            inputStream.close();
            inputStream = null;
            conn.disconnect();
            String resp = buffer.toString();
            //QQ互联获取返回参数处理
            if (resp.contains("callback( ")) {
                resp = buffer.toString().replace("callback( ", "").replace(" );", "");
            }
            jsonObject = JSONObject.parseObject(resp);
        } catch (Exception e) {
            logger.error("WxUtil.httpsRequest() happen error!", e);
        }
        return jsonObject;
    }


    /**
     * 获取接口访问凭证
     *
     * @param appId 凭证
     * @param appSecret 密钥
     * @return
     */
    public static WxToken getToken(String appId, String appSecret) {
        WxToken token = null;

        String redisKey = RedisKeys.SYS_WX_ACCESS_TOKEN.redisKey();
        try {
            String value = wxUtil.redisUtil.getString(redisKey);
            if (!VerifyUtil.isMiss(value)) {
                return JsonUtil.parse(value, WxToken.class);
            }

            String requestUrl = token_url.replace("APPID", appId).replace("APPSECRET", appSecret);
            // 发起GET请求获取凭证
            JSONObject jsonObject = httpsRequest(requestUrl, "GET", null);
            logger.info("WxUtil:getToken{}", JsonUtil.toJSONString(jsonObject));

            if (null != jsonObject) {
                token = new WxToken();
                token.setAccessToken(jsonObject.getString("access_token"));
                token.setExpiresIn(jsonObject.getInteger("expires_in"));

                wxUtil.redisUtil.set(redisKey, JsonUtil.toJSONString(token), 5, TimeUnit.MINUTES);
            }
        } catch (Exception e) {
            token = null;
            // 获取token失败
            logger.error("WxUtil.getToken() happen error!", e);
        }
        return token;
    }


    // 菜单创建（POST） 限100（次/天）
    public static String menu_create_url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";

    /**
     * 创建菜单
     *
     * @param menu 菜单实例
     * @param accessToken 有效的access_token
     * @return 0表示成功，其他值表示失败
     */
    public static int createMenu(String menu, String accessToken) {
        int result = 0;

        // 拼装创建菜单的url
        String url = menu_create_url.replace("ACCESS_TOKEN", accessToken);
        // 将菜单对象转换成json字符串
//        String jsonMenu = JSON.toJSONString(menu);
        // 调用接口创建菜单
        JSONObject jsonObject = httpsRequest(url, "POST", menu);

        if (null != jsonObject) {
            if (0 != jsonObject.getInteger("errcode")) {
                result = jsonObject.getInteger("errcode");
            }
        }
        return result;
    }

    public static String menu_get_url = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN";
    /**
     * 查询菜单
     *
     * @param accessToken 有效的access_token
     * @return 0表示成功，其他值表示失败
     */
    public static JSONObject getMenu(String accessToken) {
        int result = 0;

        // 拼装创建菜单的url
        String url = menu_get_url.replace("ACCESS_TOKEN", accessToken);
        // 将菜单对象转换成json字符串
//        String jsonMenu = JSONObject.fromObject(menu).toString();
        // 调用接口创建菜单
        JSONObject jsonObject = httpsRequest(url, "POST", null);

        return jsonObject;
    }

    public static String menu_delete_url = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN";
    /**
     * 查询菜单
     *
     * @param accessToken 有效的access_token
     * @return 0表示成功，其他值表示失败
     */
    public static int deleteMenu(String accessToken) {
        int result = 0;

        // 拼装创建菜单的url
        String url = menu_delete_url.replace("ACCESS_TOKEN", accessToken);
        // 调用接口创建菜单
        JSONObject jsonObject = httpsRequest(url, "POST", null);
        if (null != jsonObject) {
            if (0 != jsonObject.getInteger("errcode")) {
                result = jsonObject.getInteger("errcode");
            }
        }
        return result;
    }




    /*
     * 上传本地文件到微信获取mediaId
     */

    public static String upload(String appId, String appSecret, String filePath, String type) throws IOException {
        File file = new File(filePath);
        if (!file.exists() || !file.isFile()) {
            throw new IOException("文件不存在");
        }

        String url = "http://file.api.weixin.qq.com/cgi-bin/media/upload?access_token=" + getToken(appId, appSecret).getAccessToken()+"&type="+type;

        URL urlObj = new URL(url);
        //连接
        HttpURLConnection con = (HttpURLConnection) urlObj.openConnection();

        con.setRequestMethod("POST");
        con.setDoInput(true);
        con.setDoOutput(true);
        con.setUseCaches(false);

        //设置请求头信息
        con.setRequestProperty("Connection", "Keep-Alive");
        con.setRequestProperty("Charset", "UTF-8");

        //设置边界
        String BOUNDARY = "----------" + System.currentTimeMillis();
        con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);

        String sb = "--" +
                BOUNDARY +
                "\r\n" +
                "Content-Disposition: form-data;name=\"file\";filename=\"" + file.getName() + "\"\r\n" +
                "Content-Type:application/octet-stream\r\n\r\n";

        byte[] head = sb.getBytes(StandardCharsets.UTF_8);

        //获得输出流
        OutputStream out = new DataOutputStream(con.getOutputStream());
        //输出表头
        out.write(head);

        //文件正文部分
        //把文件已流文件的方式 推入到url中
        DataInputStream in = new DataInputStream(new FileInputStream(file));
        int bytes = 0;
        byte[] bufferOut = new byte[1024];
        while ((bytes = in.read(bufferOut)) != -1) {
            out.write(bufferOut, 0, bytes);
        }
        in.close();

        //结尾部分
        byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes(StandardCharsets.UTF_8);//定义最后数据分隔线

        out.write(foot);

        out.flush();
        out.close();

        StringBuffer buffer = new StringBuffer();
        BufferedReader reader = null;
        String result = null;
        try {
            //定义BufferedReader输入流来读取URL的响应
            reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
            String line = null;
            while ((line = reader.readLine()) != null) {
                buffer.append(line);
            }
            if (result == null) {
                result = buffer.toString();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                reader.close();
            }
        }

        JSONObject jsonObj = JSON.parseObject(result);
        String typeName = "media_id";
        if(!"image".equals(type)){
            typeName = type + "_media_id";
        }
        String mediaId = jsonObj.getString(typeName);
        return mediaId;
    }


    public final static String GET_USER_INFO = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID";

    public static JSONObject getUserInfo(String accessToken, String openId) {
        String requestUrl  = GET_USER_INFO.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openId);
        // 获取用户信息
        return WxUtil.httpsRequest(requestUrl, "GET", null);
    }

    
    private static final String SESSION_KEY_URL = "https://api.weixin.qq.com/sns/jscode2session";
    
    private static final OkHttpClient client = new OkHttpClient();
    
    /**
     * 获取微信小程序 session_key 和 openid
     * @param code
     * @return
     * @throws IOException 
     */
    public static JSONObject getSessionKeyOropenid(String appid, String secret, String code) throws IOException{
        //微信端登录code值
        String body= SESSION_KEY_URL+"?appid="+appid+"&secret="+secret+"&js_code="+code+"&grant_type=authorization_code";
        Request request = new Request.Builder().url(body).build();

        okhttp3.Response response = client.newCall(request).execute();
        if(response.body()!=null){
            String str=response.body().string();
            if(StringUtils.isNotEmpty(str)){
                JSONObject jo= JSON.parseObject(str);
                logger.info("getSessionKeyOropenid：{}", jo);
                return jo;
            }

        } 
        return null;
    }
    
  //获取token
    public static String getAccessToken(String appid, String secret) throws Exception {
        String access_token = "";
        String grant_type = "client_credential";//获取access_token填写client_credential
        //这个url链接地址和参数皆不能变
        String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type="+grant_type+"&appid="+appid+"&secret="+secret;  //访问链接

        URL urlGet = new URL(url);
        HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();
        http.setRequestMethod("GET"); // 必须是get方式请求
        http.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
        http.setDoOutput(true);
        http.setDoInput(true);
        /*System.setProperty("sun.net.client.defaultConnectTimeout", "30000");// 连接超时30秒
        System.setProperty("sun.net.client.defaultReadTimeout", "30000"); // 读取超时30秒 */
        http.connect();
        InputStream is = http.getInputStream();
        int size = is.available();
        byte[] jsonBytes = new byte[size];
        is.read(jsonBytes);
        String message = new String(jsonBytes, StandardCharsets.UTF_8);
        logger.info("resMeg:{}", message);
        JSONObject demoJson = JSONObject.parseObject(message);
        access_token = demoJson.getString("access_token");
        is.close();
        return access_token;
    }
    
    /**
     * 获取ticket
     * @param accessToken
     * @return
     * @throws Exception
     */
    public static String getTicket(String accessToken) throws Exception {
        String ticket = null;
        String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+ accessToken +"&type=jsapi";//这个url链接和参数不能变
        URL urlGet = new URL(url);
        HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();
        http.setRequestMethod("GET"); // 必须是get方式请求
        http.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
        http.setDoOutput(true);
        http.setDoInput(true);
        System.setProperty("sun.net.client.defaultConnectTimeout", "30000");// 连接超时30秒
        System.setProperty("sun.net.client.defaultReadTimeout", "30000"); // 读取超时30秒
        http.connect();
        InputStream is = http.getInputStream();
        int size = is.available();
        byte[] jsonBytes = new byte[size];
        is.read(jsonBytes);
        String message = new String(jsonBytes, StandardCharsets.UTF_8);
        JSONObject demoJson = JSONObject.parseObject(message);
        ticket = demoJson.getString("ticket");
        is.close();
        return ticket;
    }


    /**
     *@Description: oauth2 验证获取微信公众号accessToken和openId
     *@Param: [appid, secret, code]
     *@return: com.alibaba.fastjson.JSONObject
     *@Author: zhangyi
     *@date: 2020/7/22 17:39
     */
    public static JSONObject getOpenIdByCode(String appid, String secret, String code) throws IOException {

        //封装获取openId的微信API
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" +
                appid +
                "&secret=" +
                secret +
                "&code=" +
                code +
                "&grant_type=authorization_code";
        Request request = new Request.Builder().url(url).build();

        okhttp3.Response response = client.newCall(request).execute();
        if(response.body() != null){
            String str = response.body().string();
            if(StringUtils.isNotEmpty(str)){
                return JSON.parseObject(str);
            }
        }
        return null;
    }

}
